"""
========================================================================
FILE: geometric_field_interactor.py

LAST MODIFIED: 20 September 2009

DESCRIPTION: 
classes and functions to interact with geometric_fields in mayavi2
========================================================================
"""
"""
BEGIN LICENSE BLOCK 
Version: MPL 1.1/GPL 2.0/LGPL 2.1

The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.

The Original Code is fieldwork.

The Initial Developer of the Original Code is Ju Zhang.
Portions created by the Initial Developer are Copyright (C) 2009
the Initial Developer. All Rights Reserved.

Contributor(s):

Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.

END LICENSE BLOCK
"""

from enthought.mayavi import mlab
from enthought.tvtk.api import tvtk
import scipy

class point_picker(object):
	"""observers methods for a mayavi scene interactor. 
	Applied logic to make it record the picked position only
	if the mouse has not moved between lmb press and release.
	picks up to a user defined number of points before notifying a 
	parent class.
	"""
	
	mouse_mvt = False

	def __init__(self, picker, points_plot, figure, parent):
		self.picker = picker
		self.points_plot = points_plot
		self.parent = parent
		self.figure = figure
		self.picked_points = []
		
	def set_number_of_points_to_pick( self, n ):
		""" clears the list of picked points and defines how many points
		to pick before calling the parent's _picking_done method """
		
		self.picked_points = []
		self.n = n
		
	def on_button_press(self, obj, evt):
		self.mouse_mvt = False

	def on_mouse_move(self, obj, evt):
		self.mouse_mvt = True

	def on_button_release(self, obj, evt):
		""" if left mouse button has not moved, gets picked position
		from scene pointpicker and calculates the closest data point.
		records this data point until the number of recorded data points
		reaches self.n, where it calls self.parent._picking_done() """
		
		if not self.mouse_mvt:
			x, y = obj.GetEventPosition()
			self.picker.pick((x, y, 0), self.figure.scene.renderer)
			
			# calculate distance to all data points from picked point
			tmp = ( self.points_plot.mlab_source.points - self.picker.pick_position ) ** 2.0
			# find nearest data point
			nearest_point = tmp.sum(axis = 1).argmin()
			print 'point:', nearest_point
			self.picked_points.append( nearest_point )
			print 'points picked:', self.picked_points
			
			if len( self.picked_points ) == self.n:
				print 'adding element...'
				self.parent._picking_done()
				self.mouse_mvt = False
				return
			
			self.mouse_mvt = False

class element_adder( object ):
	""" Class for interactively adding an element to a geometric field 
	by clicking on the geometric points the new element's element points 
	will connect to. Initialise with the geometric_field object.
	"""
	
	def __init__( self, geometric_field ):
		self.gf = geometric_field
		self.element = None
		
		# initialise plot
		self.figure = mlab.figure(1)
		self.points_plot = self.gf._plot_points()
		self.field_plot = self.gf._plot_field( 10, glyph = 'sphere' )
		
		# initialise point_picker
		self.picker = point_picker( self.figure.scene.picker.pointpicker, 
								self.points_plot, self.figure, self )
		self.figure.scene.interactor.add_observer('LeftButtonPressEvent', 
                                self.picker.on_button_press)
		self.figure.scene.interactor.add_observer('MouseMoveEvent', 
                                self.picker.on_mouse_move)
		self.figure.scene.interactor.add_observer('LeftButtonReleaseEvent', 
                                self.picker.on_button_release)
		
	def add_element( self, element ):
		""" sets the point_picker for the user to select the required
		number of points """
		
		self.element = element
		# get number of points needed
		element_points = self.element.get_number_of_ensemble_points()
		print 'element requires', element_points, 'points.'
		
		self.picker.set_number_of_points_to_pick( element_points )
		mlab.show()
		
	def _picking_done( self ):
		""" once picking is done, add the element with the picked point
		numbers. Re-draws the field plot with the new element """
		
		if self.gf.add_element( self.element, self.picker.picked_points ):
			print 'element_added'
			self.field_plot.remove()
			self.field_plot = self.gf._plot_field( 10, glyph = 'sphere' )
			
		
		return 1
